﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Design;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;

using EnvDTE;
using EnvDTE80;

using Neon.Common;
using Neon.IO;
using Neon.Windows;

using Task = System.Threading.Tasks.Task;

namespace RaspberryDebugger
{
    /// <summary>
    /// 处理<b>项目/树莓调试设置… < / b >命令。  
    /// </summary>
    internal sealed class SettingsCommand
    {
        /// <summary>
        /// Command ID.
        /// </summary>
        public const int CommandId = RaspberryDebuggerPackage.SettingsCommandId;

        /// <summary>
        /// Package command set ID.
        /// </summary>
        public static readonly Guid CommandSet = RaspberryDebuggerPackage.CommandSet;

        /// <summary>
        /// VS Package that provides this command, not null.
        /// </summary>
        private readonly AsyncPackage package;

        private DTE2    dte;

        /// <summary>
        /// 初始化<see cref="SettingsCommand"/>类的一个新实例。  
        /// 添加菜单的命令处理程序(命令必须存在于命令表文件中)  
        /// </summary>
        /// <param name="package">Owner package, not null.</param>
        /// <param name="commandService">要添加命令的命令服务，不为空。</param>
        private SettingsCommand(AsyncPackage package, OleMenuCommandService commandService)
        {
            Covenant.Requires<ArgumentNullException>(package != null, nameof(package));
            Covenant.Requires<ArgumentNullException>(commandService != null, nameof(commandService));
            
            ThreadHelper.ThrowIfNotOnUIThread();

            this.package = package;
            this.dte     = (DTE2)Package.GetGlobalService(typeof(SDTE));

            var menuCommandID = new CommandID(CommandSet, CommandId);
            var menuItem      = new OleMenuCommand(this.Execute, menuCommandID);

            menuItem.BeforeQueryStatus +=
                (s, a) =>
                {
                    var command = (OleMenuCommand)s;
                        
                    command.Visible = PackageHelper.IsActiveProjectRaspberryCompatible(dte);
                };
             
            commandService.AddCommand(menuItem);
        }

        /// <summary>
        /// 获取该命令的实例。
        /// </summary>
        public static SettingsCommand Instance { get; private set; }

        /// <summary>
        /// 从所有者包获取服务提供程序。 命令的实例。  
        /// </summary>
        private Microsoft.VisualStudio.Shell.IAsyncServiceProvider ServiceProvider => this.package;

        /// <summary>
        ///初始化命令的单例。  
        /// </summary>
        /// <param name="package">Owner package, not null.</param>
        public static async Task InitializeAsync(AsyncPackage package)
        {
            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken);

            var commandService = await package.GetServiceAsync(typeof(IMenuCommandService)) as OleMenuCommandService;

            SettingsCommand.Instance = new SettingsCommand(package, commandService);
        }

        /// <summary>
        ///查看构造函数来查看菜单项是如何与这个函数关联的  
        /// OleMenuCommandService服务和MenuCommand类。  
        /// </summary>
        /// <param name="sender">Event sender.</param>
        /// <param name="e">Event args.</param>
#pragma warning disable VSTHRD100
        private async void Execute(object sender, EventArgs e)
#pragma warning restore VSTHRD100 
        {
            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

            if (dte.Solution == null)
            {
                return;
            }

            var project = PackageHelper.GetStartupProject(dte.Solution);

            if (project == null)
            {
                MessageBoxEx.Show(
                    "请使用“项目/设置为启动项目”菜单选择启动项目，或在“解决方案资源管理器”中右键单击项目并启用该选项。  ",
                    "Startup Project not found",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error);

                return;
            }

            var targetFrameworkMonikers = (string)project.Properties.Item("TargetFrameworkMoniker").Value;
            var outputType              = (int)project.Properties.Item("OutputType").Value;
            var monikers                = targetFrameworkMonikers.Split(',');
            var isNetCore               = monikers[0] == ".NETCoreApp";
            var sdkVersion              = monikers[1].StartsWith("Version=v") ? monikers[1].Substring("Version=v".Length) : null;

            if (!isNetCore ||
                outputType != 1 /* EXE */ ||
                sdkVersion == null ||
                SemanticVersion.Parse(sdkVersion) < SemanticVersion.Parse("3.1"))
            {
                MessageBoxEx.Show(
                    "此项目类型不支持树莓调试。 只支持针对.net Core 3.1或更高版本的.net Core应用程序。  ",
                    "Unsupported Project Type",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Warning);

                return;
            }

            var raspberryProjects = PackageHelper.ReadRaspberryProjects(dte.Solution);
            var projectSettings   = raspberryProjects[project.UniqueName];
            var settingsDialog    = new SettingsDialog(projectSettings);

            if (settingsDialog.ShowDialog() == DialogResult.OK)
            {
                PackageHelper.WriteRaspberryProjects(dte.Solution, raspberryProjects);
            }
        }
    }
}
